package com.derbysoft.dswitch.adapter.ihg.dswitch2.translate;

import com.derbysoft.dswitch.adapter.ihg.common.utils.CloneUtils;
import com.derbysoft.dswitch.adapter.ihg.common.utils.CollectionUtil;
import com.derbysoft.dswitch.adapter.ihg.common.utils.DateTimeUtils;
import com.derbysoft.dswitch.adapter.ihg.common.utils.DateUtils;
import com.derbysoft.dswitch.adapter.ihg.dto.Rate;
import com.derbysoft.dswitch.adapter.ihg.dto.RateChangeInfo;
import com.derbysoft.dswitch.adapter.ihg.dto.TimeSpan;
import com.derbysoft.modules.eip.translator.Translator;
import com.derbysoft.remote.dswitch.generic.dto.SimpleAmountDTO;
import com.derbysoft.remote.dswitch.hotel.constants.MealsIncludedType;
import com.derbysoft.remote.dswitch.hotel.dto.MealsIncludedDTO;
import com.derbysoft.remote.dswitch.hotel.dto.RateDTO;
import com.derbysoft.remote.share.Currency;
import com.derbysoft.remote.share.dto.DateRangeDTO;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

public class IhgRates2RateDTOsTranslator implements Translator<List<Rate>, List<RateDTO>> {

    private TimeSpan requestDateRange;

    private Date earliestRateChangeDate;

    private Date lastRateChangeDate;

    public IhgRates2RateDTOsTranslator(TimeSpan requestDateRange) {
        this.requestDateRange = requestDateRange;
    }

    @Override
    public List<RateDTO> translate(List<Rate> rates) {
        Rate rate = rates.get(0);
        List<RateChangeInfo> changeInfos = rate.getTPAExtensions().getRateChangeInfo();
        List<RateDTO> result = new ArrayList<RateDTO>();
        if (CollectionUtil.isEmpty(changeInfos)) {
            result.add(createRateDTO(rate, DateTimeUtils.parse(requestDateRange.getStart()), DateTimeUtils.parse(requestDateRange.getEnd())));
            return result;
        }
        parseChangeInfos(changeInfos);
        initEarliestAndLastRateChange(changeInfos);
        if (earliestRateChangeDate.after(DateTimeUtils.parse(requestDateRange.getStart()))) {
            result.add(createRateDTO(rate, DateTimeUtils.parse(requestDateRange.getStart()), earliestRateChangeDate));
        }
        Date previousEnd = null;
        for (RateChangeInfo rateChangeInfo : changeInfos) {
            if (previousEnd != null && previousEnd.before(DateTimeUtils.parse(rateChangeInfo.getStart()))) {
                result.add(createRateDTO(rate, previousEnd, DateTimeUtils.parse(rateChangeInfo.getStart())));
            }
            result.add(createRateDTO(
                    rateChangeInfo.getAmount(),
                    rateChangeInfo.getCurrencyCode(),
                    DateTimeUtils.parse(rateChangeInfo.getStart()),
                    DateTimeUtils.parse(rateChangeInfo.getEnd())
            ));
            previousEnd = DateTimeUtils.parse(rateChangeInfo.getEnd());
        }
        if (lastRateChangeDate.before(DateTimeUtils.parse(requestDateRange.getEnd()))) {
            result.add(createRateDTO(rate, CloneUtils.clone(lastRateChangeDate), DateTimeUtils.parse((requestDateRange.getEnd()))));
        }
        return result;
    }

    private void parseChangeInfos(List<RateChangeInfo> changeInfos) {
        for (RateChangeInfo changeInfo : changeInfos) {
            processEffectivePeriod(changeInfo);
            processRateChange(changeInfo);
        }
    }

    private void processEffectivePeriod(RateChangeInfo changeInfo) {
        String effectivePeriod = null;
        if (changeInfo.getEffectivePeriod() != null) {
            try {
                effectivePeriod = changeInfo.getEffectivePeriod().trim();
                changeInfo.setEffectivePeriod(effectivePeriod);
                effectivePeriod = effectivePeriod.replaceAll("EFFECTIVE: ", "");
                String[] split = effectivePeriod.split(",");
                changeInfo.setStart(DateTimeUtils.formatDate(getDateFormat().parse(split[0])));
                changeInfo.setEnd(DateTimeUtils.formatDate(getDateFormat().parse(split[1])));
            } catch (Exception e) {
                throw new IllegalArgumentException("The argument EffectivePeriod format is illegal, "
                        + "that should be 'EFFECTIVE: 2007-01-12,2007-26-12' ,but this is[" + effectivePeriod + "]", e);
            }
        }
    }

    public static DateFormat getDateFormat() {
        return new SimpleDateFormat("yyyy-dd-MM");
    }

    private void processRateChange(RateChangeInfo changeInfo) {
        String rateChangeText = null;
        try {
            rateChangeText = changeInfo.getRateChange().trim();
            rateChangeText = rateChangeText.replaceAll("Rate Change: ", "");
            String[] split = rateChangeText.split(" ");
            changeInfo.setAmount(new BigDecimal(split[0]));
            changeInfo.setCurrencyCode(split[1]);
        } catch (Exception e) {
            throw new IllegalArgumentException("The argument RateChange format is illegal, "
                    + "that should be 'Rate Change: 1195.00 CNY' ,but this is[" + rateChangeText + "]", e);
        }
    }

    private RateDTO createRateDTO(BigDecimal amount, String currencyCode, Date star, Date end) {
        RateDTO rateDTO = new RateDTO();
        rateDTO.setMealsIncluded(new MealsIncludedDTO(MealsIncludedType.UNKNOWN));
        rateDTO.setDateRange(new DateRangeDTO(star, DateUtils.prev(end)));
        rateDTO.setPureAmount(new SimpleAmountDTO(amount, Currency.fromCode(currencyCode)));
        return rateDTO;
    }

    private RateDTO createRateDTO(Rate rate, Date star, Date end) {
        return createRateDTO(rate.getBase().getAmountBeforeTax(), rate.getBase().getCurrencyCode(), star, end);
    }

    private void initEarliestAndLastRateChange(List<RateChangeInfo> rateChangeInfos) {
        Comparator<RateChangeInfo> comparator = new Comparator<RateChangeInfo>() {
            public int compare(RateChangeInfo o1, RateChangeInfo o2) {
                return DateTimeUtils.parse(o1.getStart()).compareTo(DateTimeUtils.parse(o2.getStart()));
            }
        };
        Collections.sort(rateChangeInfos, comparator);
        earliestRateChangeDate = DateTimeUtils.parse(rateChangeInfos.get(0).getStart());
        lastRateChangeDate = DateTimeUtils.parse(rateChangeInfos.get(rateChangeInfos.size() - 1).getEnd());
    }
}
